home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / streaming / qtspacketizerreassembler / componentvideortp / sources / rtpmpcomponentvideo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  32.0 KB  |  1,181 lines

  1. /*
  2.     File:        RTPMPComponentVideo.c
  3.  
  4.     Contains:    Definition of Component Video RTPMediaPacketizer
  5.  
  6.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  7.     
  8.     
  9.     
  10.     OVERVIEW
  11.     
  12.     QuickTime Streaming software uses an RTPMediaPacketizer to encapsulate
  13.     sample data in network packets.  When preparing to packetize sample data,
  14.     Streaming software first determines a packetizer's capabilities and
  15.     operational parameters.  If the packetizer is suitable, the Streaming
  16.     software provides the packetizer with an RTPPacketBuilder.  The packetizer
  17.     uses the RTPPacketBuilder to construct network packets from sample data.
  18.     The Streaming software specifies what sample data to packetize by calling
  19.     the packetizer's RTPMPSetSampleData() implementation.
  20.     
  21.     This packetizer implements the following interface and delegates all other
  22.     calls to a base RTPMediaPacketizer defined by QuickTime Streaming.
  23.         
  24.         
  25.         STANDARD COMPONENT INTERFACE
  26.         ----------------------------
  27.         
  28.         CallComponentOpen()                Allocate and initialize storage for
  29.                                         instance variables.
  30.         
  31.         CallComponentClose()            Reverse the effects of
  32.                                         CallComponentOpen().
  33.         
  34.         CallComponentVersion()            Return the instance's version.
  35.         
  36.         CallComponentTarget()            Update the instance's inheritance graph.
  37.         
  38.         
  39.         
  40.         RTP MEDIA PACKETIZER INTERFACE
  41.         ------------------------------
  42.         
  43.         RTPMPInitialize()                Prepare to packetize sample data.
  44.         
  45.         RTPMPPreflightMedia()            Determine whether the packetizer can
  46.                                         packetize the described data.
  47.         
  48.         RTPMPSetSampleData()            Use the instance's RTPPacketBuilder to
  49.                                         packetize sample data.
  50.         
  51.         RTPMPFlush()                    Finish any packetization in progress.
  52.         
  53.         RTPMPReset()                    Abort any packetization in progress.
  54.         
  55.         RTPMPGetInfo()                    Return the requested information.
  56.         
  57.         RTPMPSetTimeScale()
  58.         
  59.         RTPMPGetTimeScale()
  60.         
  61.         RTPMPSetTimeBase()
  62.         
  63.         RTPMPGetTimeBase()
  64.         
  65.         RTPMPHasCharacteristic()
  66.         
  67.         RTPMPSetPacketBuilder()
  68.         
  69.         RTPMPGetPacketBuilder()
  70.         
  71.         RTPMPSetMediaType()
  72.         
  73.         RTPMPGetMediaType()
  74.         
  75.         RTPMPSetMaxPacketSize()
  76.         
  77.         RTPMPGetMaxPacketSize()
  78.         
  79.         RTPMPSetMaxPacketDuration()
  80.         
  81.         RTPMPGetMaxPacketDuration()        
  82. */
  83.  
  84.  
  85.  
  86. /* ---------------------------------------------------------------------------
  87.  *        H E A D E R S
  88.  * ---------------------------------------------------------------------------
  89.  */
  90.  
  91. #include "RTPMPComponentVideo.h"
  92. #include "RTPMPComponentVideoResources.h"
  93.  
  94.  
  95.  
  96. /* ---------------------------------------------------------------------------
  97.  *        R T P    M E D I A    P A C K E T I Z E R    P R O T O T Y P E S
  98.  * ---------------------------------------------------------------------------
  99.  *
  100.  *    QTStreamingComponents.k.h uses these macros to declare prototypes for
  101.  *    the RTPMediaPacketizer calls defined in this file.
  102.  *
  103.  */
  104.  
  105. #define RTPMP_BASENAME()                RTPMPComponentVideo_
  106. #define RTPMP_GLOBALS()                    RTPMPComponentVideoInstanceData **
  107.  
  108. #include <QTStreamingComponents.k.h>
  109.  
  110.  
  111.  
  112. /* ---------------------------------------------------------------------------
  113.  *        C O M P O N E N T    D I S P A T C H    H E L P E R
  114.  * ---------------------------------------------------------------------------
  115.  *
  116.  *    ComponentDispatchHelper.c uses these macros to define a dispatcher and to
  117.  *    declare prototypes for the core component calls defined in this file.  For
  118.  *    Mac OS, it defines the routine descriptor that serves as the component
  119.  *    entry point.  The name of the routine descriptor is the macro expansion of
  120.  *        
  121.  *        CALLCOMPONENT_BASENAME()##ComponentDispatchRD
  122.  *    
  123.  *    The name of the dispatcher is the macro expansion of
  124.  *    
  125.  *        CALLCOMPONENT_BASENAME()##ComponentDispatch
  126.  *
  127.  */
  128.  
  129. #define CALLCOMPONENT_BASENAME()        RTPMP_BASENAME()
  130. #define CALLCOMPONENT_GLOBALS()            RTPMP_GLOBALS() storage
  131. #define COMPONENT_DISPATCH_FILE            "RTPMPComponentVideoDispatch.h"
  132. #define COMPONENT_C_DISPATCHER            1
  133. #define COMPONENT_UPP_SELECT_ROOT()        RTPMP
  134. #define GET_DELEGATE_COMPONENT()        ( ( **storage ).itsBase )
  135.  
  136. #include <ComponentDispatchHelper.c>
  137.  
  138.  
  139.  
  140. #pragma mark *        INTERNAL IMPLEMENTATION
  141. #pragma mark -
  142. /* ---------------------------------------------------------------------------
  143.  *        I N T E R N A L    I M P L E M E N T A T I O N
  144.  * ---------------------------------------------------------------------------
  145.  */
  146.  
  147. enum
  148. {
  149.     __kNoLimit                        = 0xFFFFFFFF,
  150.     __kNoFlags                        = 0,
  151.     __kDefaultPacketDurationLimit    = __kNoLimit,
  152.     __kPayloadDataSizeMask            = 0xFFFFFFFC,
  153.     __kTypicalMTUSize                = 1500,            /* Ethernet */
  154.     __kTypicalNetworkHeaderSize        = 20,            /* IP, no options */
  155.     __kTypicalTransportHeaderSize    = 8,            /* UDP */
  156.     __kTypicalRTPHeaderSize            = 12,            /* no CSRCs, no extension */
  157.     __kDefaultPacketSizeLimit        =
  158.         __kTypicalMTUSize - __kTypicalNetworkHeaderSize - __kTypicalTransportHeaderSize -
  159.         __kTypicalRTPHeaderSize
  160. };
  161.  
  162.  
  163.  
  164. /* ---------------------------------------------------------------------------
  165.  *        __UpdateDataSizes()
  166.  * ---------------------------------------------------------------------------
  167.  *
  168.  *    Update data sizes the instance uses to construct network packets.
  169.  *
  170.  */
  171.  
  172. static
  173. void
  174. __UpdateDataSizes(
  175.     RTPMPComponentVideoInstanceData **    inGlobals )
  176. {
  177.     UInt16    theWidth;
  178.     UInt16    theHeight;
  179.     
  180.     
  181.     theWidth = ComponentVideoPayloadWidth( &( **inGlobals ).itsPayloadHeader );
  182.     theHeight = ComponentVideoPayloadHeight( &( **inGlobals ).itsPayloadHeader );
  183.     
  184.     
  185.     /*    YUV 4:2:2 encoding uses four octets to represent a pair of pixels.
  186.          The number of octets in a frame is therefore
  187.          
  188.              padded-width x height x 2 octets
  189.          
  190.          where padded-width is the row width in pixels padded to an
  191.          even number. */
  192.     
  193.     ( **inGlobals ).itsFrameDataSize =
  194.         ( ( ( theWidth + 1 ) & ( ~1L ) ) * theHeight ) << 1;
  195.     
  196.     
  197.     /*    This packetizer sends an integral number of sample packets in
  198.         each network packet.  Since YUV 4:2:2 encodes samples in four-octet
  199.         sample packets, the amount of data sent in a network packet will be
  200.         a multiple of four octets.  Most network packets will carry a fixed
  201.         header and enough sample data to fill the network packet as closely
  202.         as possible to the network packet size limit. */
  203.     
  204.     ( **inGlobals ).itsPayloadDataSize =
  205.         ( ( **inGlobals ).itsPacketSizeLimit -
  206.             sizeof( ( **inGlobals ).itsPayloadHeader.itsFixedHeader ) ) &
  207.         __kPayloadDataSizeMask;
  208.     
  209.     
  210.     /*    Whatever data would be left over after dividing a frame into
  211.         maximal-length network packets must fit into the first packet along
  212.         with a fixed header and a payload description.   If the leftover
  213.         data won't fit, adjust the size of the other network packets. */
  214.     
  215.     while(
  216.         ( ( ( **inGlobals ).itsFrameDataSize % ( **inGlobals ).itsPayloadDataSize ) +
  217.             sizeof( ( **inGlobals ).itsPayloadHeader ) >
  218.         ( **inGlobals ).itsPacketSizeLimit ) )
  219.     {
  220.         ( **inGlobals ).itsPayloadDataSize -= 4;
  221.     }
  222. }
  223.  
  224.  
  225.  
  226. /* ---------------------------------------------------------------------------
  227.  *        __UpdateSampleDescription()
  228.  * ---------------------------------------------------------------------------
  229.  *
  230.  *    Determine whether the SampleDescription of incoming sample data has
  231.  *    changed and update instance variables accordingly.
  232.  *
  233.  */
  234.  
  235. static
  236. ComponentResult
  237. __UpdateSampleDescription(
  238.     RTPMPComponentVideoInstanceData **    inGlobals,
  239.     const RTPMPSampleDataParams *        inSampleData )
  240. {
  241.     ComponentResult            theError = noErr;
  242.     SInt32                    theFlags;
  243.     ImageDescriptionHandle    theDescription;
  244.     
  245.     
  246.     /*    Check the SampleDescription if it is the first description or if the cached
  247.         sample description seed doesn't match the current seed. */
  248.     
  249.     if(
  250.         !ComponentVideoPayloadHasDescription( &( **inGlobals ).itsPayloadHeader )  ||
  251.         ( **inGlobals ).itsSampleDescriptionSeed != inSampleData->sampleDescSeed )
  252.     {
  253.         theDescription =
  254.             REINTERPRET_CAST( ImageDescriptionHandle )( inSampleData->sampleDescription );
  255.         
  256.         
  257.         /* Only update if the differences in the new SampleDescription are pertinent. */
  258.         
  259.         if(
  260.             ComponentVideoPayloadWidth( &( **inGlobals ).itsPayloadHeader ) !=
  261.                 ( **theDescription ).width  ||
  262.             ComponentVideoPayloadHeight( &( **inGlobals ).itsPayloadHeader ) !=
  263.                 ( **theDescription ).height )
  264.         {
  265.             /*    If the RTPMPSetSampleData() implementation queues data, then any
  266.                 queued sample data, which uses the obsolete SampleDescription, must
  267.                 be flushed before updating to the new SampleDescription. */
  268.             
  269.             theError = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
  270.             
  271.             if( !theError )
  272.             {
  273.                 /*    Update the payload description that the packetizer includes in
  274.                     some network packets. */
  275.                 
  276.                 ComponentVideoPayloadSetDescription(
  277.                     &( **inGlobals ).itsPayloadHeader, ( **theDescription ).width,
  278.                     ( **theDescription ).height );
  279.                 
  280.                 
  281.                 /*    Update data sizes the packetizer uses to construct network
  282.                     packets. */
  283.                 
  284.                 __UpdateDataSizes( inGlobals );
  285.             }
  286.         }
  287.         
  288.         
  289.         /*    Update the cached sample description seed to indicate that the
  290.             packetizer state is now consistent with the new SampleDescription. */
  291.         
  292.         if( !theError )
  293.             ( **inGlobals ).itsSampleDescriptionSeed = inSampleData->sampleDescSeed;
  294.     }
  295.     
  296.     return( theError );
  297. }
  298.  
  299.  
  300.  
  301. /* ---------------------------------------------------------------------------
  302.  *        __PacketizeSampleData()
  303.  * ---------------------------------------------------------------------------
  304.  *
  305.  *    Construct network packets from the specified sample data.
  306.  *
  307.  */
  308.  
  309. static
  310. ComponentResult
  311. __PacketizeSampleData(
  312.     RTPMPComponentVideoInstanceData **    inGlobals,
  313.     const RTPMPSampleDataParams *        inSampleData )
  314. {
  315.     ComponentResult            theError;
  316.     RTPPacketGroupRef        thePacketGroup;
  317.     UInt32                    theDataOffset;
  318.     RTPPacketRef            thePacket;
  319.     UInt32                    theDataSize;
  320.     ComponentVideoPayload    theHeader;
  321.     UInt32                    theHeaderSize;
  322.     
  323.     
  324.     /* This packetizer sends all the data for one frame in a single packet group. */
  325.     
  326.     theError =
  327.         RTPPBBeginPacketGroup(
  328.             ( **inGlobals ).itsPacketBuilder, __kNoFlags, inSampleData->timeStamp,
  329.             &thePacketGroup );
  330.     
  331.     if( !theError )
  332.     {
  333.         /*    Most network packets for the frame will be uniformly sized, with a
  334.             fixed header and a fixed amount of sample data.  The first network
  335.             packet will include whatever data is left over (taken from the
  336.             start of the sample data, not the end), as well as a fixed header
  337.             and a payload description. */
  338.         
  339.         theDataOffset = 0;
  340.         theDataSize = ( **inGlobals ).itsFrameDataSize % ( **inGlobals ).itsPayloadDataSize;
  341.         
  342.         theHeader = ( **inGlobals ).itsPayloadHeader;
  343.         theHeaderSize = sizeof( theHeader );
  344.         
  345.         
  346.         /*    Construct network packets until the sample data for this frame is exhausted. */
  347.         
  348.         while( theDataOffset < ( **inGlobals ).itsFrameDataSize  &&  !theError )
  349.         {
  350.             theError =
  351.                 RTPPBBeginPacket(
  352.                     ( **inGlobals ).itsPacketBuilder, __kNoFlags, thePacketGroup,
  353.                     ( **inGlobals ).itsPacketSizeLimit, &thePacket );
  354.             
  355.             if( !theError )
  356.             {
  357.                 /*    The header (with optional payload description) is added to the
  358.                     network packet as literal data.  The data is written directly
  359.                     to the network packet.  If the RTPPacketBuilder is storing
  360.                     network packet data to disk, it must store a copy of literal data. */
  361.                 
  362.                 theError =
  363.                     RTPPBAddPacketLiteralData(
  364.                         ( **inGlobals ).itsPacketBuilder, __kNoFlags, thePacketGroup,
  365.                         thePacket, REINTERPRET_CAST( UInt8 * )( &theHeader ),
  366.                         theHeaderSize, NULL );
  367.                 
  368.                 if( !theError )
  369.                 {
  370.                     /*    The RTPPacketBuilder provides a routine specifically for adding
  371.                         sample data.  For stored movies, the RTPPacketBuilder need not
  372.                         store a copy of sample data, since the data is already stored
  373.                         in the movie. */
  374.                     
  375.                     theError =
  376.                         RTPPBAddPacketSampleData(
  377.                             ( **inGlobals ).itsPacketBuilder, __kNoFlags, thePacketGroup,
  378.                             thePacket, CONST_CAST( RTPMPSampleDataParams * )( inSampleData ),
  379.                             theDataOffset, theDataSize, NULL );
  380.                     
  381.                     if( !theError )
  382.                     {
  383.                         /*    The packetizer sets the RTP/AVP marker bit in the last network
  384.                             packet of a frame.  The QuickTime Streaming base RTPReassembler
  385.                             can better assist in reassembling the payload data if this bit
  386.                             is used to mark the end of a packet group.
  387.                             
  388.                             Most payloads have no duration, except for the last payload,
  389.                             which absorbs the duration for the entire frame. */
  390.                         
  391.                         if( theDataOffset + theDataSize < ( **inGlobals ).itsFrameDataSize )
  392.                         {
  393.                             theError =
  394.                                 RTPPBEndPacket(
  395.                                     ( **inGlobals ).itsPacketBuilder, __kNoFlags,
  396.                                     thePacketGroup, thePacket, 0 /* inTimeOffset */,
  397.                                     0 /* inDuration */ );
  398.                         }
  399.                         
  400.                         else
  401.                         {
  402.                             theError =
  403.                                 RTPPBEndPacket(
  404.                                     ( **inGlobals ).itsPacketBuilder, kRTPPBSetMarkerFlag,
  405.                                     thePacketGroup, thePacket, 0 /* inTimeOffset */,
  406.                                     inSampleData->duration );
  407.                         }
  408.                     }
  409.                 }
  410.             }
  411.             
  412.             
  413.             /*    For this packetizer, packets after the first network packet of a frame
  414.                 are uniformly sized and have no payload description. */
  415.             
  416.             if( theDataOffset )
  417.             {
  418.                 theDataOffset += theDataSize;
  419.             }
  420.             
  421.             else
  422.             {
  423.                 theDataOffset += theDataSize;
  424.                 theDataSize = ( **inGlobals ).itsPayloadDataSize;
  425.                 theHeaderSize = sizeof( theHeader.itsFixedHeader );
  426.                 
  427.                 ComponentVideoPayloadSetDescription( &theHeader, 0, 0 );
  428.             }
  429.             
  430.             
  431.             /*    Update the Offset field of the header to indicate the next block
  432.                 of sample data. */
  433.             
  434.             ComponentVideoPayloadSetOffset( &theHeader, theDataOffset );
  435.         }
  436.         
  437.         
  438.         if( theError )
  439.         {
  440.             RTPPBEndPacketGroup(
  441.                 ( **inGlobals ).itsPacketBuilder, kRTPPBDontSendFlag, thePacketGroup );
  442.         }
  443.         
  444.         else
  445.         {
  446.             /*    For this packetizer, every group contains only sync samples.  That
  447.                 means the sample data for the group can be decoded independently of
  448.                 any previous sample data.  When randomly accessing stored movies,
  449.                 a streaming server can look for sync samples. */
  450.             
  451.             theError =
  452.                 RTPPBEndPacketGroup(
  453.                     ( **inGlobals ).itsPacketBuilder, kRTPPBSyncSampleFlag, thePacketGroup );
  454.         }
  455.     }
  456.     
  457.     return( theError );
  458. }
  459.  
  460.  
  461.  
  462. #pragma mark -
  463. #pragma mark *        STANDARD COMPONENT INTERFACE
  464. #pragma mark -
  465. /* ---------------------------------------------------------------------------
  466.  *        S T A N D A R D    C O M P O N E N T    I N T E R F A C E
  467.  * ---------------------------------------------------------------------------
  468.  */
  469.  
  470. /* ---------------------------------------------------------------------------
  471.  *        + CallComponentOpen() implementation
  472.  * ---------------------------------------------------------------------------
  473.  *
  474.  *    Allocate and initialize storage for instance variables.  When a packetizer
  475.  *    is opened, it is not always called to packetize data, so this function
  476.  *    doesn't perform any allocations or time-consuming operations that are
  477.  *    needed only for packetizing sample data.  The RTPMPInitialize()
  478.  *    implementation performs such operations.
  479.  *
  480.  */
  481.  
  482. EXTERN_API( ComponentResult )
  483. RTPMPComponentVideo_Open(
  484.     RTPMPComponentVideoInstanceData **    inGlobals,
  485.     ComponentInstance                    self )
  486. {
  487.     ComponentResult        theResult = noErr;
  488.     RTPMediaPacketizer    theBase;
  489.     
  490.     
  491.     inGlobals =
  492.         REINTERPRET_CAST( RTPMPComponentVideoInstanceData ** )(
  493.             NewHandleClear( sizeof( **inGlobals ) ) );
  494.     
  495.     if( inGlobals )
  496.     {
  497.         ( **inGlobals ).itself = self;
  498.         ( **inGlobals ).itsFinalDerivation = self;
  499.         ( **inGlobals ).itsInitialized = false;
  500.         
  501.         SetComponentInstanceStorage( self, REINTERPRET_CAST( Handle )( inGlobals ) );
  502.         
  503.         theResult =
  504.             OpenADefaultComponent(
  505.                 kRTPMediaPacketizerType, kRTPBaseMediaPacketizerType, &theBase );
  506.         
  507.         if( theResult == noErr )
  508.         {
  509.             ( **inGlobals ).itsBase = theBase;
  510.             theResult = CallComponentTarget( ( **inGlobals ).itsBase, self );
  511.         }
  512.     }
  513.     
  514.     else
  515.     {
  516.         theResult = MemError();
  517.         
  518.         if( theResult == noErr )
  519.             theResult = memFullErr;
  520.     }
  521.     
  522.     return( theResult );
  523. }
  524.  
  525.  
  526.  
  527. /* ---------------------------------------------------------------------------
  528.  *        + CallComponentClose() implementation
  529.  * ---------------------------------------------------------------------------
  530.  *
  531.  *    Reverse the effects of the CallComponentOpen() implementation.
  532.  *
  533.  */
  534.  
  535. EXTERN_API( ComponentResult )
  536. RTPMPComponentVideo_Close(
  537.     RTPMPComponentVideoInstanceData **    inGlobals,
  538.     ComponentInstance                    self )
  539. {
  540. #pragma unused( self )
  541.     
  542.     if( inGlobals )
  543.     {
  544.         if( ( **inGlobals ).itsBase )
  545.             CloseComponent( ( **inGlobals ).itsBase );
  546.         
  547.         DisposeHandle( REINTERPRET_CAST( Handle )( inGlobals ) );
  548.     }
  549.     
  550.     return( noErr );
  551. }
  552.  
  553.  
  554.  
  555. /* ---------------------------------------------------------------------------
  556.  *        + CallComponentVersion() implementation
  557.  * ---------------------------------------------------------------------------
  558.  *
  559.  *    Return the instance's version.
  560.  *
  561.  */
  562.  
  563. EXTERN_API( ComponentResult )
  564. RTPMPComponentVideo_Version(
  565.     RTPMPComponentVideoInstanceData **    inGlobals )
  566. {
  567. #pragma unused( inGlobals )
  568.     
  569.     return( kComponentVersion );
  570. }
  571.  
  572.  
  573.  
  574. /* ---------------------------------------------------------------------------
  575.  *        + CallComponentTarget() implementation
  576.  * ---------------------------------------------------------------------------
  577.  *
  578.  *    Update the instance's inheritance graph with a new most-derived instance.
  579.  *
  580.  */
  581.  
  582. EXTERN_API( ComponentResult )
  583. RTPMPComponentVideo_Target(
  584.     RTPMPComponentVideoInstanceData **    inGlobals,
  585.     ComponentInstance                    target )
  586. {
  587.     ComponentResult        theResult;
  588.     
  589.     
  590.     if( ( **inGlobals ).itsBase )
  591.         theResult = ComponentSetTarget( ( **inGlobals ).itsBase, target );
  592.     else
  593.         theResult = noErr;
  594.     
  595.     if( theResult == noErr )
  596.         ( **inGlobals ).itsFinalDerivation = target;
  597.     
  598.     return( theResult );
  599. }
  600.  
  601.  
  602.  
  603. #pragma mark -
  604. #pragma mark *        RTP MEDIA PACKETIZER INTERFACE
  605. #pragma mark -
  606. /* ---------------------------------------------------------------------------
  607.  *        R T P    M E D I A    P A C K E T I Z E R    I N T E R F A C E
  608.  * ---------------------------------------------------------------------------
  609.  */
  610.  
  611. /* ---------------------------------------------------------------------------
  612.  *        + RTPMPInitialize() implementation
  613.  * ---------------------------------------------------------------------------
  614.  *
  615.  *    Prepare to packetize sample data.  This implementation initializes
  616.  *    instance variables that represent the packetization state.
  617.  *
  618.  */
  619.  
  620. EXTERN_API( ComponentResult )
  621. RTPMPComponentVideo_Initialize(
  622.     RTPMPComponentVideoInstanceData **    inGlobals,
  623.     SInt32                                inFlags )
  624. {
  625.     ComponentResult        theResult;
  626.     
  627.     
  628.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPInitializeSelect ) )
  629.         theResult = RTPMPInitialize( ( **inGlobals ).itsBase, inFlags );
  630.     else
  631.         theResult = noErr;
  632.     
  633.     if( theResult == noErr )
  634.     {
  635.         ( **inGlobals ).itsPacketBuilder = NULL;
  636.         ( **inGlobals ).itsPacketSizeLimit = __kDefaultPacketSizeLimit;
  637.         ( **inGlobals ).itsPacketDurationLimit = __kDefaultPacketDurationLimit;
  638.         
  639.         ComponentVideoPayloadInitialize( &( **inGlobals ).itsPayloadHeader, 0, 0 );
  640.         
  641.         ( **inGlobals ).itsInitialized = true;
  642.     }
  643.     
  644.     return( theResult );
  645. }
  646.  
  647.  
  648.  
  649. /* ---------------------------------------------------------------------------
  650.  *        + RTPMPPreflightMedia() implementation
  651.  * ---------------------------------------------------------------------------
  652.  *
  653.  *    Determine whether the packetizer can packetize data described by the
  654.  *    given SampleDescription.  This implementation verifies that the sample
  655.  *    data is in Component Video format, and that the image has positive width
  656.  *    and height.
  657.  *
  658.  */
  659.  
  660. EXTERN_API( ComponentResult )
  661. RTPMPComponentVideo_PreflightMedia(
  662.     RTPMPComponentVideoInstanceData **    inGlobals,
  663.     OSType                                inMediaType,
  664.     SampleDescriptionHandle                inSampleDescription )
  665. {
  666. #pragma unused( inGlobals )
  667.     
  668.     ComponentResult            theResult;
  669.     ImageDescriptionHandle    theDescription;
  670.     
  671.     
  672.     theDescription = REINTERPRET_CAST( ImageDescriptionHandle )( inSampleDescription );
  673.     
  674.     if(
  675.         inMediaType != VideoMediaType  ||
  676.         ( **theDescription ).cType != kComponentVideoDataFormat )
  677.     {
  678.         theResult = qtsUnsupportedDataTypeErr;
  679.     }
  680.     
  681.     else if( ( **theDescription ).width <= 0  ||  ( **theDescription ).height <= 0 )
  682.     {
  683.         theResult = qtsUnsupportedFeatureErr;
  684.     }
  685.     
  686.     else
  687.     {
  688.         theResult = noErr;
  689.     }
  690.     
  691.     return( theResult );
  692. }
  693.  
  694.  
  695.  
  696. /* ---------------------------------------------------------------------------
  697.  *        + RTPMPSetSampleData() implementation
  698.  * ---------------------------------------------------------------------------
  699.  *
  700.  *    Use the instance's RTPPacketBuilder to packetize the sample data described
  701.  *    by the RTPMPSampleDataParams parameter.  The sample time of the data in
  702.  *    successive calls is non-decreasing.  In the case of Component Video, this
  703.  *    function is called with parameters describing one frame of data at a time.
  704.  *    
  705.  *    The RTPMPSampleDataParams structure includes a SampleDescription.  This
  706.  *    implementation calls __UpdateSampleDescription() to detect when the
  707.  *    SampleDescription changes and to make any updates necessary to accomodate
  708.  *    the new SampleDescription.
  709.  *
  710.  *    The function then calls __PacketizeSampleData() to divide the data into
  711.  *    network packets using the instance's RTPPacketBuilder.
  712.  *
  713.  */
  714.  
  715. EXTERN_API( ComponentResult )
  716. RTPMPComponentVideo_SetSampleData(
  717.     RTPMPComponentVideoInstanceData **    inGlobals,
  718.     const RTPMPSampleDataParams *        inSampleData,
  719.     SInt32 *                            outFlags )
  720. {
  721.     ComponentResult                theError = noErr;
  722.     
  723.     
  724.     /* Ignore requests that have no data */
  725.     
  726.     if( inSampleData->dataLength )
  727.     {
  728.         theError = __UpdateSampleDescription( inGlobals, inSampleData );
  729.         
  730.         if( !theError )
  731.             theError = __PacketizeSampleData( inGlobals, inSampleData );
  732.     }
  733.     
  734.     *outFlags = 0;
  735.     
  736.     return( theError );
  737. }
  738.  
  739.  
  740.  
  741. /* ---------------------------------------------------------------------------
  742.  *        + RTPMPFlush() implementation
  743.  * ---------------------------------------------------------------------------
  744.  *
  745.  *    Finish any packetization in progress.  This packetizer doesn't defer any
  746.  *    packetization, so its RTPMPFlush() implementation just gives its base a
  747.  *    chance to flush.
  748.  *
  749.  */
  750.  
  751. EXTERN_API( ComponentResult )
  752. RTPMPComponentVideo_Flush(
  753.     RTPMPComponentVideoInstanceData **    inGlobals,
  754.     SInt32                inFlags,
  755.     SInt32 *            outFlags )
  756. {
  757.     ComponentResult        theResult;
  758.     
  759.     
  760.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPFlushSelect ) )
  761.     {
  762.         theResult = RTPMPFlush( ( **inGlobals ).itsBase, inFlags, outFlags );
  763.     }
  764.     
  765.     else
  766.     {
  767.         theResult = noErr;
  768.         *outFlags = 0;
  769.     }
  770.     
  771.     return( theResult );
  772. }
  773.  
  774.  
  775.  
  776. /* ---------------------------------------------------------------------------
  777.  *        + RTPMPReset() implementation
  778.  * ---------------------------------------------------------------------------
  779.  *
  780.  *    Abort any packetization in progress and prepare to packetize a new data
  781.  *    stream.  This implementation reinitializes its packetization state and
  782.  *    resets its base.
  783.  *
  784.  */
  785.  
  786. EXTERN_API( ComponentResult )
  787. RTPMPComponentVideo_Reset(
  788.     RTPMPComponentVideoInstanceData **    inGlobals,
  789.     SInt32                                inFlags )
  790. {
  791.     ComponentResult        theResult;
  792.     
  793.     
  794.     ComponentVideoPayloadInitialize( &( **inGlobals ).itsPayloadHeader, 0, 0 );
  795.     
  796.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPResetSelect ) )
  797.         theResult = RTPMPReset( ( **inGlobals ).itsBase, inFlags );
  798.     else
  799.         theResult = noErr;
  800.     
  801.     return( theResult );
  802. }
  803.  
  804.  
  805.  
  806. /* ---------------------------------------------------------------------------
  807.  *        + RTPMPGetInfo() implementation
  808.  * ---------------------------------------------------------------------------
  809.  *
  810.  *    Return the information indicated by the selector.  This implemenation
  811.  *    computes a result for the following selectors and delegates all others to
  812.  *    its base.
  813.  *
  814.  *
  815.  *        kRTPMPPayloadTypeInfo    ioParams points to an RTPMPPayloadTypeParams
  816.  *                                structure.  This implementation fills in this
  817.  *                                structure to indicate it uses a dynamic AVP
  818.  *                                payload type.  It copies its payload encoding
  819.  *                                name to a buffer described by this structure.
  820.  *
  821.  *        kRTPMPRTPTimeScaleInfo    ioParams points to a TimeScale where the
  822.  *                                implementation returns the clock rate, in
  823.  *                                Hertz, to be used for RTP timestamps.
  824.  *
  825.  *        kRTPMPMinPayloadSize    ioParams points to a UInt32 where the
  826.  *                                implementation returns the number of octets
  827.  *                                needed for the fixed header and payload
  828.  *                                description used by this packetizer.
  829.  *
  830.  *        kRTPMPPayloadNameInfo    ioParams points to a Str255 where the
  831.  *                                implementation returns a human-readable name
  832.  *                                for the payload encoding used by this
  833.  *                                packetizer.
  834.  *
  835.  */
  836.  
  837. EXTERN_API( ComponentResult )
  838. RTPMPComponentVideo_GetInfo(
  839.     RTPMPComponentVideoInstanceData **    inGlobals,
  840.     OSType                                inSelector,
  841.     void *                                ioParams )
  842. {
  843.     ComponentResult                theError = noErr;
  844.     RTPMPPayloadTypeParams *    thePayloadInfo;
  845.     Str255                        theEncodingName;
  846.     
  847.     
  848.     switch( inSelector )
  849.     {
  850.         case kRTPMPPayloadTypeInfo:
  851.             thePayloadInfo = STATIC_CAST( RTPMPPayloadTypeParams * )( ioParams );
  852.             thePayloadInfo->flags = kRTPPayloadTypeDynamicFlag;
  853.             thePayloadInfo->payloadNumber = kRTPPayload_Unknown;
  854.             
  855.             theError =
  856.                 GetComponentIndString(
  857.                     REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
  858.                     theEncodingName, kRTPMPComponentVideoStringListResource,
  859.                     kRTPMPComponentVideoProtocolEncodingString );
  860.             
  861.             if( !theError )
  862.             {
  863.                 if( thePayloadInfo->nameLength < ( theEncodingName[ 0 ] + 1 ) )
  864.                 {
  865.                     theError = paramErr;
  866.                 }
  867.                 
  868.                 else
  869.                 {
  870.                     BlockMoveData(
  871.                         &theEncodingName[ 1 ], thePayloadInfo->payloadName,
  872.                         theEncodingName[ 0 ] );
  873.                     
  874.                     thePayloadInfo->payloadName[ theEncodingName[ 0 ] ] = '\0';
  875.                 }
  876.                 
  877.                 thePayloadInfo->nameLength = theEncodingName[ 0 ] + 1;
  878.             }
  879.         break;
  880.         
  881.         
  882.         case kRTPMPRTPTimeScaleInfo:
  883.             *STATIC_CAST( TimeScale * )( ioParams ) = kComponentVideoRTPTimeScale;
  884.         break;
  885.         
  886.         
  887.         case kRTPMPMinPayloadSize:
  888.             *STATIC_CAST( UInt32 * )( ioParams ) = sizeof( ComponentVideoPayload );
  889.         break;
  890.         
  891.         
  892.         case kRTPMPPayloadNameInfo:
  893.             theError =
  894.                 GetComponentIndString(
  895.                     REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
  896.                     STATIC_CAST( StringPtr )( ioParams ),
  897.                     kRTPMPComponentVideoStringListResource,
  898.                     kRTPMPComponentVideoHIEncodingString );
  899.         break;
  900.         
  901.         
  902.         case kRTPMPRequiredSampleDescriptionInfo:
  903.         case kRTPMPMinPacketDuration:
  904.         case kRTPMPSuggestedRepeatPktCountInfo:
  905.         case kRTPMPSuggestedRepeatPktSpacingInfo:
  906.         case kRTPMPMaxPartialSampleSizeInfo:
  907.         case kRTPMPPreferredBufferDelayInfo:
  908.         default:
  909.             theError =
  910.                 RTPMPGetInfo( ( **inGlobals ).itsBase, inSelector, ioParams );
  911.         break;
  912.     }
  913.     
  914.     return( theError );
  915. }
  916.  
  917.  
  918.  
  919. /* ---------------------------------------------------------------------------
  920.  *        + RTPMPSetTimeScale() implementation
  921.  * ---------------------------------------------------------------------------
  922.  */
  923.  
  924. EXTERN_API( ComponentResult )
  925. RTPMPComponentVideo_SetTimeScale(
  926.     RTPMPComponentVideoInstanceData **    inGlobals,
  927.     TimeScale                            inTimeScale )
  928. {
  929.     ( **inGlobals ).itsMediaTimeScale = inTimeScale;
  930.     
  931.     return( noErr );
  932. }
  933.  
  934.  
  935.  
  936. /* ---------------------------------------------------------------------------
  937.  *        + RTPMPGetTimeScale() implementation
  938.  * ---------------------------------------------------------------------------
  939.  */
  940.  
  941. EXTERN_API( ComponentResult )
  942. RTPMPComponentVideo_GetTimeScale(
  943.     RTPMPComponentVideoInstanceData **    inGlobals,
  944.     TimeScale *                            outTimeScale )
  945. {
  946.     *outTimeScale = ( **inGlobals ).itsMediaTimeScale;
  947.     
  948.     return( noErr );
  949. }
  950.  
  951.  
  952.  
  953. /* ---------------------------------------------------------------------------
  954.  *        + RTPMPSetTimeBase() implementation
  955.  * ---------------------------------------------------------------------------
  956.  */
  957.  
  958. EXTERN_API( ComponentResult )
  959. RTPMPComponentVideo_SetTimeBase(
  960.     RTPMPComponentVideoInstanceData **    inGlobals,
  961.     TimeBase                            inTimeBase )
  962. {
  963.     ( **inGlobals ).itsMediaTimeBase = inTimeBase;
  964.     
  965.     return( noErr );
  966. }
  967.  
  968.  
  969.  
  970. /* ---------------------------------------------------------------------------
  971.  *        + RTPMPGetTimeBase() implementation
  972.  * ---------------------------------------------------------------------------
  973.  */
  974.  
  975. EXTERN_API( ComponentResult )
  976. RTPMPComponentVideo_GetTimeBase(
  977.     RTPMPComponentVideoInstanceData **    inGlobals,
  978.     TimeBase *                            outTimeBase )
  979. {
  980.     *outTimeBase = ( **inGlobals ).itsMediaTimeBase;
  981.     
  982.     return( noErr );
  983. }
  984.  
  985.  
  986.  
  987. /* ---------------------------------------------------------------------------
  988.  *        + RTPMPHasCharacteristic() implementation
  989.  * ---------------------------------------------------------------------------
  990.  */
  991.  
  992. EXTERN_API( ComponentResult )
  993. RTPMPComponentVideo_HasCharacteristic(
  994.     RTPMPComponentVideoInstanceData **    inGlobals,
  995.     OSType                                inSelector,
  996.     Boolean *                            outHasIt )
  997. {
  998.     ComponentResult        theResult = noErr;
  999.     
  1000.     
  1001.     switch( inSelector )
  1002.     {
  1003.         case kRTPMPNoSampleDataRequiredCharacteristic:
  1004.             *outHasIt = true;
  1005.         break;
  1006.         
  1007.         
  1008.         case kRTPMPPartialSamplesRequiredCharacteristic:
  1009.         case kRTPMPHasUserSettingsDialogCharacteristic:
  1010.         case kRTPMPPrefersReliableTransportCharacteristic:
  1011.         case kRTPMPRequiresOutOfBandDimensionsCharacteristic:
  1012.             *outHasIt = false;
  1013.         break;
  1014.         
  1015.         
  1016.         default:
  1017.             theResult =
  1018.                 RTPMPHasCharacteristic( ( **inGlobals ).itsBase, inSelector, outHasIt );
  1019.         break;
  1020.     }
  1021.     
  1022.     return( theResult );
  1023. }
  1024.  
  1025.  
  1026.  
  1027. /* ---------------------------------------------------------------------------
  1028.  *        + RTPMPSetPacketBuilder() implementation
  1029.  * ---------------------------------------------------------------------------
  1030.  */
  1031.  
  1032. EXTERN_API( ComponentResult )
  1033. RTPMPComponentVideo_SetPacketBuilder(
  1034.     RTPMPComponentVideoInstanceData **    inGlobals,
  1035.     ComponentInstance                    inPacketBuilder )
  1036. {
  1037.     ComponentResult        theError;
  1038.     SInt32                theFlags;
  1039.     
  1040.     
  1041.     if( ( **inGlobals ).itsInitialized  &&  ( **inGlobals ).itsPacketBuilder )
  1042.         theError = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
  1043.     else
  1044.         theError = noErr;
  1045.     
  1046.     if( !theError )
  1047.         ( **inGlobals ).itsPacketBuilder = inPacketBuilder;
  1048.     
  1049.     return( theError );
  1050. }
  1051.  
  1052.  
  1053.  
  1054. /* ---------------------------------------------------------------------------
  1055.  *        + RTPMPGetPacketBuilder() implementation
  1056.  * ---------------------------------------------------------------------------
  1057.  */
  1058.  
  1059. EXTERN_API( ComponentResult )
  1060. RTPMPComponentVideo_GetPacketBuilder(
  1061.     RTPMPComponentVideoInstanceData **    inGlobals,
  1062.     ComponentInstance *                    outPacketBuilder )
  1063. {
  1064.     *outPacketBuilder = ( **inGlobals ).itsPacketBuilder;
  1065.     
  1066.     return( noErr );
  1067. }
  1068.  
  1069.  
  1070.  
  1071. /* ---------------------------------------------------------------------------
  1072.  *        + RTPMPSetMediaType() implementation
  1073.  * ---------------------------------------------------------------------------
  1074.  */
  1075.  
  1076. EXTERN_API( ComponentResult )
  1077. RTPMPComponentVideo_SetMediaType(
  1078.     RTPMPComponentVideoInstanceData **    inGlobals,
  1079.     OSType                                inMediaType )
  1080. {
  1081. #pragma unused( inGlobals )
  1082.     ComponentResult        theResult;
  1083.     
  1084.     
  1085.     if( inMediaType == VideoMediaType )
  1086.         theResult = noErr;
  1087.     else
  1088.         theResult = qtsBadDataErr;
  1089.     
  1090.     return( theResult );
  1091. }
  1092.  
  1093.  
  1094.  
  1095. /* ---------------------------------------------------------------------------
  1096.  *        + RTPMPGetMediaType() implementation
  1097.  * ---------------------------------------------------------------------------
  1098.  */
  1099.  
  1100. EXTERN_API( ComponentResult )
  1101. RTPMPComponentVideo_GetMediaType(
  1102.     RTPMPComponentVideoInstanceData **    inGlobals,
  1103.     OSType *                            outMediaType )
  1104. {
  1105. #pragma unused(inGlobals)
  1106.  
  1107.     *outMediaType = VideoMediaType;
  1108.     
  1109.     return( noErr );
  1110. }
  1111.  
  1112.  
  1113.  
  1114. /* ---------------------------------------------------------------------------
  1115.  *        + RTPMPSetMaxPacketSize() implementation
  1116.  * ---------------------------------------------------------------------------
  1117.  */
  1118.  
  1119. EXTERN_API( ComponentResult )
  1120. RTPMPComponentVideo_SetMaxPacketSize(
  1121.     RTPMPComponentVideoInstanceData **    inGlobals,
  1122.     UInt32                                inMaxPacketSize )
  1123. {
  1124.     ( **inGlobals ).itsPacketSizeLimit = inMaxPacketSize;
  1125.     
  1126.     __UpdateDataSizes( inGlobals );
  1127.     
  1128.     return( noErr );
  1129. }
  1130.  
  1131.  
  1132.  
  1133. /* ---------------------------------------------------------------------------
  1134.  *        + RTPMPGetMaxPacketSize() implementation
  1135.  * ---------------------------------------------------------------------------
  1136.  */
  1137.  
  1138. EXTERN_API( ComponentResult )
  1139. RTPMPComponentVideo_GetMaxPacketSize(
  1140.     RTPMPComponentVideoInstanceData **    inGlobals,
  1141.     UInt32 *                            outMaxPacketSize )
  1142. {
  1143.     *outMaxPacketSize = ( **inGlobals ).itsPacketSizeLimit;
  1144.     
  1145.     return( noErr );
  1146. }
  1147.  
  1148.  
  1149.  
  1150. /* ---------------------------------------------------------------------------
  1151.  *        + RTPMPSetMaxPacketDuration() implementation
  1152.  * ---------------------------------------------------------------------------
  1153.  */
  1154.  
  1155. EXTERN_API( ComponentResult )
  1156. RTPMPComponentVideo_SetMaxPacketDuration(
  1157.     RTPMPComponentVideoInstanceData **    inGlobals,
  1158.     UInt32                                inMaxPacketDuration )
  1159. {
  1160.     ( **inGlobals ).itsPacketDurationLimit = inMaxPacketDuration;
  1161.     
  1162.     return( noErr );
  1163. }
  1164.  
  1165.  
  1166.  
  1167. /* ---------------------------------------------------------------------------
  1168.  *        + RTPMPGetMaxPacketDuration() implementation
  1169.  * ---------------------------------------------------------------------------
  1170.  */
  1171.  
  1172. EXTERN_API( ComponentResult )
  1173. RTPMPComponentVideo_GetMaxPacketDuration(
  1174.     RTPMPComponentVideoInstanceData **    inGlobals,
  1175.     UInt32 *                            outMaxPacketDuration )
  1176. {
  1177.     *outMaxPacketDuration = ( **inGlobals ).itsPacketDurationLimit;
  1178.     
  1179.     return( noErr );
  1180. }
  1181.